package service

import (
	"dc-news/common/global/consts"
	myjwt "dc-news/common/middleware/jwt"
	"dc-news/common/resp"
	"dc-news/common/utils"
	"dc-news/dao"
	"dc-news/dao/model"
	"dc-news/vo"
	"github.com/gin-gonic/gin"
	"github.com/spf13/cast"
	"go.uber.org/zap"
	"math/rand"
	"net/http"
	"time"
)

//TODO:避免新闻重复

// GetNewsListByChannelService 通过频道获取新闻列表
func GetNewsListByChannelService(c *gin.Context, channel string, count int) {
	list, err := dao.GetNewsIdListByChannelAndCount(count, channel)
	if err != nil {
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误！"))
		zap.S().Error("通过频道获取新闻列表错误: ", err)
		return
	}
	abstracts := make([]model.NewsAbstract, 0)
	for _, id := range list {
		abstract, err := dao.GetNewsAbstractById(id)
		if err != nil {
			c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误！"))
			zap.S().Error("通过频道获取新闻列表错误: ", err)
			return
		}
		abstracts = append(abstracts, *abstract)
	}
	c.JSON(http.StatusOK, vo.NewGetNewsListResp(&abstracts))
}

// GetNewsListByRecommendService 获取推荐新闻列表
func GetNewsListByRecommendService(c *gin.Context, count int) {
	claims := c.MustGet("claims").(*myjwt.CustomClaims)
	channels, err := dao.GetChannelsByUserId(cast.ToInt(claims.Id))
	if err != nil {
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误！"))
		zap.S().Error("获取推荐新闻列表错误: ", err)
		return
	}
	recommendCount := 0
	if len(channels) != 0 {
		recommendCount = int(float32(count) * 0.5)
	}
	recommendIdMap := getNewsCountByChannels(channels, recommendCount)
	ids := make([]int, 0)
	for k, v := range recommendIdMap {
		l, _ := dao.GetNewsIdListByChannelAndCount(v, k)
		ids = append(ids, l...)
	}
	l, _ := dao.GetNewsIdListByChannelAndCount(count-recommendCount, "__all__")
	ids = append(ids, l...)
	abstracts := make([]model.NewsAbstract, 0)
	utils.Shuffle(ids)
	for _, id := range ids {
		abstract, err := dao.GetNewsAbstractById(id)
		if err != nil {
			c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误！"))
			zap.S().Error("获取推荐新闻列表错误: ", err)
			return
		}
		abstracts = append(abstracts, *abstract)
	}
	c.JSON(http.StatusOK, vo.NewGetNewsListResp(&abstracts))
}

// GetNewsService 获取新闻
//TODO:异步写入记录到数据库
func GetNewsService(c *gin.Context, id int) {
	claims := c.MustGet("claims").(*myjwt.CustomClaims)
	news, err := dao.GetNewsById(id)
	if err != nil {
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误！"))
		zap.S().Error("获取新闻错误: ", err)
		return
	}
	if cast.ToInt(claims.Id) != 0 {
		SaveRecordToDB(cast.ToInt(claims.Id), time.Now().Unix(), news)
	}
	c.JSON(http.StatusOK, vo.NewGetNews(news))
}

// AddFavouriteNewsService 添加收藏
func AddFavouriteNewsService(c *gin.Context, userId int, newsId int) {
	err := dao.AddFavouriteNewsByUserIdAndNewsId(userId, newsId)
	if err != nil {
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误！"))
		zap.S().Error("添加新闻收藏错误: ", err)
		return
	}
	c.JSON(http.StatusOK, resp.NewOkResp())
}

// RemoveFavouriteNewsService 取消收藏
func RemoveFavouriteNewsService(c *gin.Context, userId int, newsId int) {
	err := dao.RemoveFavouriteNewsByUserIdAndNewsId(userId, newsId)
	if err != nil {
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误！"))
		zap.S().Error("添加新闻收藏错误: ", err)
		return
	}
	c.JSON(http.StatusOK, resp.NewOkResp())
}

// AddChannelService 关注频道
func AddChannelService(c *gin.Context, userId int, req *vo.AddChannelReq) {
	err := dao.AddChannelByUserId(userId, req.Channel)
	if err != nil {
		if errStr := err.Error()[:10]; errStr == "Error 1062" {
			c.JSON(http.StatusOK, resp.NewErrResp(consts.FailCode, "不可重复关注"))
			return
		}
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误"))
		zap.L().Error(err.Error())
		return
	}
	c.JSON(http.StatusOK, resp.NewOkResp())
}

// RemoveChannelService 取消关注频道
func RemoveChannelService(c *gin.Context, userId int, req *vo.RemoveChannelReq) {
	err := dao.RemoveChannelByUserId(userId, req.Channel)
	if err != nil {
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误"))
		zap.L().Error(err.Error())
		return
	}
	c.JSON(http.StatusOK, resp.NewOkResp())
}

// LikesNewsService 点赞新闻
func LikesNewsService(c *gin.Context, userId int, newsId int) {
	err := dao.LikesNewsByUserIdAndNewsId(userId, newsId)
	if err != nil {
		if err.Error() == "has been liked" {
			c.JSON(http.StatusOK, resp.NewErrResp(consts.FailCode, "不可重复点赞"))
			return
		}
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误"))
		zap.L().Error(err.Error())
		return
	}
	c.JSON(http.StatusOK, resp.NewOkResp())
}

// CancelLikesNewsService 取消点赞新闻
func CancelLikesNewsService(c *gin.Context, userId int, newsId int) {
	err := dao.CancelLikesNewsByUserIdAndNewsId(userId, newsId)
	if err != nil {
		if err.Error() == "has not been liked" {
			c.JSON(http.StatusOK, resp.NewErrResp(consts.FailCode, "未点赞此新闻"))
			return
		}
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误"))
		zap.L().Error(err.Error())
		return
	}
	c.JSON(http.StatusOK, resp.NewOkResp())
}

// GetNewsInfoService 获取新闻点赞收藏信息
func GetNewsInfoService(c *gin.Context, id int) {
	claims := c.MustGet("claims").(*myjwt.CustomClaims)
	if claims.Id == "" {
		c.JSON(http.StatusOK, vo.NewGetNewsInfoResp(false, false))
		return
	}
	isLike, isFavourite, err := dao.GetNewsInfoByUserIdAndNewsId(cast.ToInt(claims.Id), id)
	if err != nil {
		zap.S().Error("获取新闻点赞收藏信息错误：", err)
		c.JSON(http.StatusOK, resp.NewErrResp(consts.ServerErrorCode, "服务器错误"))
		return
	}
	c.JSON(http.StatusOK, vo.NewGetNewsInfoResp(isLike, isFavourite))
}

//随机获取推荐的新闻
func getNewsCountByChannels(channels []string, count int) map[string]int {
	m := make(map[int]string)
	res := make(map[string]int)
	if count < 1 {
		return res
	}
	rand.Seed(time.Now().Unix())
	for i := 0; i < len(channels); i++ {
		m[i] = channels[i]
	}
	arr := make([]int, len(channels))
	for i := 0; i < count; i++ {
		arr[rand.Intn(len(channels))]++
	}
	for k, v := range m {
		res[v] = arr[k]
	}
	return res
}
